package com.yykj.user.center.server.service.impl.patient;

import com.yykj.common.constant.RedisConstant;
import com.yykj.common.dto.CreateAccountDTO;
import com.yykj.common.enums.ResultEnums;
import com.yykj.common.exception.NormalException;
import com.yykj.common.service.RedisService;
import com.yykj.common.service.TencentService;
import com.yykj.common.util.GsonUtil;
import com.yykj.common.util.LocalStringUtil;
import com.yykj.common.vo.PageData;
import com.yykj.common.vo.ResultVO;
import com.yykj.message.center.client.dto.MessageDTO;
import com.yykj.message.center.client.feign.MessageFeignClient;
import com.yykj.tencent.im.client.feign.TencentImFeignClient;
import com.yykj.tencent.im.client.form.UserProfileForm;
import com.yykj.user.center.client.dto.PatientInfoDto;
import com.yykj.user.center.server.dto.CodeInfo;
import com.yykj.user.center.server.dto.PatientCardInfoDTO;
import com.yykj.user.center.server.dto.PatientDTO;
import com.yykj.user.center.server.dto.UserLoginInfo;
import com.yykj.user.center.server.emun.RoleType;
import com.yykj.user.center.server.form.DisablePatient;
import com.yykj.user.center.server.form.RegisterForm;
import com.yykj.user.center.server.form.RelaceAvatarForm;
import com.yykj.user.center.server.form.UserLoginForm;
import com.yykj.user.center.server.model.Patient;
import com.yykj.user.center.server.model.PatientCardInfo;
import com.yykj.user.center.server.repository.patient.PatientCardInfoRepository;
import com.yykj.user.center.server.repository.patient.PatientRepository;
import com.yykj.user.center.server.service.patient.LoginService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author chenl
 * @version 1.0
 * @date 2021/10/20 22:24
 */
@Service
@Slf4j
public class LoginServiceImpl implements LoginService {
    @Autowired
    private PatientRepository patientRepository;

    @Autowired
    private RedisService redisService;
    @Autowired
    private MessageFeignClient messageFeignClient;
    @Autowired
    private PatientCardInfoRepository patientCardInfoRepository;
    @Autowired
    private TencentService tencentService;
    @Autowired
    TencentImFeignClient tencentImFeignClient;


    @Value("${spring.profiles.active}")
    private String prefix;

    @Override
    public UserLoginInfo login(UserLoginForm form) {
        String token = LocalStringUtil.getUUID();
        if (form.getHospitalId() == null) {
            throw new NormalException(ResultEnums.NO_HOSPITALID);
        }
//        Patient patient = patientRepository.findFirstByAccountAndHospitalId(form.getMobile(), form.getHospitalId());
        Patient patient = patientRepository.findFirstByOpenidAndHospitalId(form.getOpenid(),form.getHospitalId());
        if (patient == null) {
            throw new NormalException(ResultEnums.LOGIN_FAIL);
        }
        String tencentAccountId = patient.getTencentAccountId();
        if(StringUtils.isEmpty(tencentAccountId)){
            patient.setTencentAccountId(prefix + patient.getId());
            CreateAccountDTO createAccountDTO = this.tencentService.createAccount(patient.getTencentAccountId(), patient.getNickName(), patient.getAvatar());
            if (createAccountDTO.getErrorCode() == 0) {//创建成功
                patientRepository.save(patient);
            } else {//创建失败
                throw new NormalException(ResultEnums.TENCENT_ACCOUNT_CREATE_ERROR);
            }
            UserProfileForm userProfileForm = UserProfileForm.builder()
                    .client("patient")
                    .fromAccount(patient.getTencentAccountId())
                    .name(patient.getNickName())
                    .image(patient.getAvatar())
                    .officer("")
                    .hospital("")
                    .depName("")
                    .phone(patient.getMobile()).build();
            this.tencentImFeignClient.setProfile(userProfileForm);
        }
        UserLoginInfo info = new UserLoginInfo();
        BeanUtils.copyProperties(patient, info);
        info.setToken(token);
        info.setUserId(patient.getId());
        info.setRole(RoleType.PATIENT.getCode());
        info.setNickname(patient.getNickName());
        info.setUserSign(this.tencentService.getUserSign(patient.getTencentAccountId()));
        redisService.set(token, GsonUtil.toJson(info));
        return info;
    }

    @Override
    public Boolean isRegister(UserLoginForm form) {
        Patient patient = patientRepository.findByOpenidAndHospitalId(form.getOpenid(),form.getHospitalId());
        if (patient == null) {
            return false;
        }
        return true;
    }

    @Override
    public String getCode(String mobile) {
        if (StringUtils.isBlank(mobile)) {
            throw new NormalException(ResultEnums.NO_MOBILE_ERROR);
        }
        ResultVO<MessageDTO> resultVO = messageFeignClient.getCode(mobile);
        String code = ((MessageDTO) resultVO.getData()).getCode();
        String time = ((MessageDTO) resultVO.getData()).getTime();
        String token = LocalStringUtil.getUUID();
        CodeInfo codeInfo = new CodeInfo();
        codeInfo.setToken(token);
        codeInfo.setMobile(mobile);
        codeInfo.setCode(code);
        redisService.set(token, GsonUtil.toJson(codeInfo), RedisConstant.MESSAGE_EXPIRE);
        log.info("手机号为：{}  注册成功，获取验证码为：{}", mobile, code);
        return token;
    }

    @Override
    public UserLoginInfo register(RegisterForm registerForm) {
        String mobile = registerForm.getMobile();
        String code = registerForm.getCode();
        String token = registerForm.getToken();
        Integer hospitalId = registerForm.getHospitalId();
        String openid = registerForm.getOpenid();
        String nickName = registerForm.getNickName();
        String avatar = registerForm.getAvatar();
        Patient patientBean = patientRepository.findByOpenidAndHospitalId(openid,hospitalId);
        String loginToken = LocalStringUtil.getUUID();
        if (patientBean != null) {
            throw new NormalException(ResultEnums.REGISTERED_ERROR);
        }
        if (registerForm.getHospitalId() == null) {
            throw new NormalException(ResultEnums.NO_HOSPITALID);
        }
        if (StringUtils.isBlank(mobile)) {
            throw new NormalException(ResultEnums.NO_MOBILE_ERROR);
        }
        if (StringUtils.isBlank(code)) {
            throw new NormalException(ResultEnums.NO_CODE_ERROR);
        }
        if (StringUtils.isBlank(token)) {
            throw new NormalException(ResultEnums.NO_TOKEN_ERROR);
        }
        if (StringUtils.isBlank(openid)) {
            throw new NormalException(ResultEnums.NO_OPENID_ERROR);
        }
        if (StringUtils.isBlank(nickName)) {
            throw new NormalException(ResultEnums.NO_NICKNAME_ERROR);
        }
        if (StringUtils.isBlank(avatar)) {
            throw new NormalException(ResultEnums.NO_AVATAR_ERROR);
        }
        String codeInfoString = redisService.get(token);
        if (StringUtils.isBlank(codeInfoString)) {
            throw new NormalException(ResultEnums.NO_GETCODE_ERROR);
        }
        CodeInfo codeInfo = GsonUtil.fromJson(codeInfoString, CodeInfo.class);
        String rCode = codeInfo.getCode();
        String rMobile = codeInfo.getMobile();
        if (rCode.equals(code) && rMobile.equals(mobile)) {
            UserLoginInfo userLoginInfo = new UserLoginInfo();
            String id = LocalStringUtil.getUUID();
            userLoginInfo.setUserId(id);
            Patient patient = new Patient();
            patient.setAccount(mobile);
            patient.setMobile(mobile);
            patient.setAddTime(LocalDateTime.now());
            patient.setHospitalId(hospitalId);
            patient.setAvatar(registerForm.getAvatar());
            patient.setNickName(registerForm.getNickName());
            patient.setId(id);
            patient.setOpenid(openid);
            patient.setTencentAccountId(prefix + id);
            CreateAccountDTO createAccountDTO = this.tencentService.createAccount(patient.getTencentAccountId(), patient.getNickName(), patient.getAvatar());
            if (createAccountDTO.getErrorCode() == 0) {//创建成功
                patientRepository.save(patient);
            } else {//创建失败
                throw new NormalException(ResultEnums.TENCENT_ACCOUNT_CREATE_ERROR);
            }
            UserProfileForm userProfileForm = UserProfileForm.builder()
                    .client("patient")
                    .fromAccount(patient.getTencentAccountId())
                    .name(patient.getNickName())
                    .image(patient.getAvatar())
                    .officer("")
                    .hospital("")
                    .depName("")
                    .phone(patient.getMobile()).build();
            this.tencentImFeignClient.setProfile(userProfileForm);
            redisService.set(loginToken, GsonUtil.toJson(patient), RedisConstant.TOKEN_EXPIRE);
            userLoginInfo.setToken(loginToken);
            userLoginInfo.setAvatar(avatar);
            userLoginInfo.setOpenid(openid);
            userLoginInfo.setNickname(nickName);
            userLoginInfo.setRole("patient");
            userLoginInfo.setMobile(mobile);
            userLoginInfo.setHospitalId(hospitalId);
            return userLoginInfo;
        }else{
            throw new NormalException(ResultEnums.REGISTER_FAILED);
        }
    }

    @Override
    public UserLoginInfo codeLogin(UserLoginForm form) {
        if (form == null) {
            throw new NormalException(ResultEnums.NO_MOBILE_ERROR);
        }
        if (StringUtils.isBlank(form.getMobile())) {
            throw new NormalException(ResultEnums.NO_MOBILE_ERROR);
        }
        if (StringUtils.isBlank(form.getCode())) {
            throw new NormalException(ResultEnums.NO_CODE_ERROR);
        }
        if (StringUtils.isBlank(form.getToken())) {
            throw new NormalException(ResultEnums.NO_TOKEN_ERROR);
        }
        if (form.getHospitalId() == null) {
            throw new NormalException(ResultEnums.NO_HOSPITALID);
        }
        String token = form.getToken();
        String codeInfoString = redisService.get(token);
        if (StringUtils.isBlank(codeInfoString)) {
            throw new NormalException(ResultEnums.NO_GETCODE_ERROR);
        }
        CodeInfo codeInfo = GsonUtil.fromJson(codeInfoString, CodeInfo.class);
        String rCode = codeInfo.getCode();
        String loginToken = LocalStringUtil.getUUID();
        Patient patient = new Patient();
        UserLoginInfo userLoginInfo = new UserLoginInfo();
        if (form.getCode().equals(rCode)) {
            patient = patientRepository.findByAccountAndHospitalId(form.getMobile(), form.getHospitalId());
            if (patient != null) {
                userLoginInfo.setUserId(patient.getId());
                userLoginInfo.setToken(loginToken);
                userLoginInfo.setHospitalId(form.getHospitalId());
                userLoginInfo.setRole(RoleType.PATIENT.getDisplay());
                redisService.set(loginToken, GsonUtil.toJson(userLoginInfo), RedisConstant.TOKEN_EXPIRE);
            } else {
                throw new NormalException(ResultEnums.NO_REGISTERED_ERROR);
            }

        }
        return userLoginInfo;
    }

    @Override
    public Boolean replaceAvatar(RelaceAvatarForm relaceAvatarForm) {
        Patient patient = patientRepository.findById(relaceAvatarForm.getId()).orElse(null);
        if(patient!=null){
            patient.setAvatar(relaceAvatarForm.getAvatar());
            patientRepository.save(patient);
        }
        return true;
    }

    @Override
    public PageData<PatientDTO> getByHospitalId(Integer current,Integer size,String name,String mobile,Integer hospitalId) {
        Pageable pageable = PageRequest.of(current, size, Sort.by(Sort.Order.desc("addTime")));
        Page<Patient> list = patientRepository.findAll(new Specification<Patient>() {
            @Override
            public Predicate toPredicate(Root<Patient> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                List<Predicate> predicateList = new ArrayList<>();
                predicateList.add(builder.equal(root.get("hospitalId"), hospitalId));
                if(org.apache.commons.lang3.StringUtils.isNotBlank(name)){
                    predicateList.add(builder.like(root.get("nickName"), name));
                }
                if (org.apache.commons.lang3.StringUtils.isNotBlank(mobile)) {
                    predicateList.add(builder.like(root.get("mobile"),mobile));
                }
                Predicate[] predicates = new Predicate[predicateList.size()];
                return query.where(predicateList.toArray(predicates)).getRestriction();
            }
        }, pageable);
        List<PatientDTO> patientDTOS = new ArrayList<>();
        for (Patient patient : list.getContent()) {
            PatientDTO patientDTO = new PatientDTO();
            BeanUtils.copyProperties(patient, patientDTO);
            patientDTOS.add(patientDTO);
        }
        PageData<PatientDTO> page = new PageData();
        page.setList(patientDTOS);
        page.setCurrentPage(current);
        page.setPageSize(size);
        page.setTotalCount(list.getTotalElements());
        return page;
    }

    @Override
    public Boolean disable(DisablePatient disablePatient) {
        Patient patient = patientRepository.findById(disablePatient.getId()).orElse(null);
        if(patient!=null){
            patient.setState(2);
            patientRepository.save(patient);
        }
        return true;
    }

    @Override
    public List<PatientCardInfoDTO> getRelation(String id) {
        List<PatientCardInfo> patientCardInfos = patientCardInfoRepository.findAllByAccountIdAndState(id,true);
        List<PatientCardInfoDTO> patientCardInfoDTOS = new ArrayList<>();
        for(PatientCardInfo patientCardInfo:patientCardInfos){
            PatientCardInfoDTO patientCardInfoDTO = new PatientCardInfoDTO();
            BeanUtils.copyProperties(patientCardInfo,patientCardInfoDTO);
            patientCardInfoDTOS.add(patientCardInfoDTO);
        }
        return patientCardInfoDTOS;
    }

    @Override
    public PatientInfoDto patientInfo(String patientId) {
        Optional<Patient> optional = this.patientRepository.findById(patientId);
        if(optional.isPresent()){
            PatientInfoDto patientInfoDto = new PatientInfoDto();
            BeanUtils.copyProperties(optional.get(), patientInfoDto);
            return patientInfoDto;
        }
        return null;
    }
}
